"""Header_Information
------------------------------------
    File_Name: jwt
    Author: RR9
    Date: 2024/10/19
    Description: 
------------------------------------
"""

from datetime import datetime, timedelta, timezone
from fastapi import HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi import Depends
import jwt
from jwt.exceptions import InvalidTokenError
from tortoise.exceptions import DoesNotExist
from tortoise.transactions import in_transaction

from app.core import config
from app.schemas.login import TokenData
from app.models.user import User
from app.schemas.login import UserInDB
from app.core.security import verify_password

SECRET_KEY = config.SECRET_KEY
ALGORITHM = config.ALGORITHM
ACCESS_TOKEN_EXPIRE_MINUTES = config.ACCESS_TOKEN_EXPIRE_MINUTES

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/v2/token")


def get_user(db):
    """用户信息
    :param db: 数据库查询的用户信息
    :return: 用户数据模型
    """
    if db:
        print('db::', db)
        return UserInDB(**db)


def authenticate_user(db, password: str):
    """验证用户

    :param db: 数据库查询的用户信息-字典
    :param password: 前端输入密码
    :return:
    """
    user = get_user(db)
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user


def create_access_token(data: dict, expires_delta: timedelta = None):
    """ 创建token """
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


async def verify_token(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效的验证凭据",
        headers={"WWW-Authenticate": "Bearer"}
    )
    try:
        payload = jwt.decode(token, config.SECRET_KEY, algorithms=[ALGORITHM])
        userid = payload.get("userid")
        username = payload.get("username")
        if userid is None:
            raise credentials_exception
        token_data = TokenData(userid=userid, username=username)
    except InvalidTokenError:
        print('99999')
        raise credentials_exception
    async with in_transaction() as conn:
        try:
            user = await User.get(userid=token_data.userid, disabled=False).values('userid', 'username', 'hashed_password', 'disabled')
        except DoesNotExist:
            user = None
        except Exception as e:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
    if user is None:
        raise credentials_exception
    return user
